The Let's Play Archive

EXAPUNKS

by Carbon dioxide

Part 11: Лрикладной Семиотики

Part 11 - Лрикладной Семиотики


=== Trash World Inbox ===

Talisriel posted:

I did have another method to show for the achievement on Zebros:
code:
LINK 800
LINK 800
COPY 800 X
REPL PRINTER
ADDI 1 X X
REPL PRINTER
ADDI 1 X X
REPL PRINTER
ADDI 1 X X
REPL PRINTER
HALT
MARK PRINTER
LINK X
MARK WHEEE
COPY 9999 #COPY
JUMP WHEEE
Since the code is designed to go infinite we don't get evaluated, so it's harder to weigh efficiency, but I think this is the first time that we can meaningfully exploit LINKing to a Variable.
Yeah, so if you remember, this is for the TONER_LOW achievement you get by sending print jobs to #COPY constantly. Since LINKs use numbers like any other you can just create them with addition operators and everything.

Talisriel posted:

While I can't really contribute to the cause of optimization, I can contribute an alternate method. Weighing in at 357/20/1, I used the SWIZ function to retrieve my row/column data out of a single digit X:
code:
GRAB 300
LINK 800
MARK LOOP
SWIZ X 2 T
COPY T #DATA
SWIZ X 1 T
COPY T #DATA
COPY 0 T
COPY F #DATA
ADDI 1 X X
SWIZ X 1 T
TEST T = 9
FJMP NEOL
ADDI 1 X X
MARK NEOL
TEST EOF
TJMP CLEAR
JUMP LOOP
MARK CLEAR
WIPE
The original version of the code, up until I was copying it into this post, included a COPY 0 #CLRS line after the link to wipe the screen, but a quick check confirmed that Ember's file overwrites thoroughly enough that I didn't need it. You'll also note that I cheated not being able to run in base 8 with a test for when we got to the 9th slot, and added one to wrap to the next line (which I expect is where most of my extra cycles came from relative to your div/modi method).
Interesting solution I wouldn't have thought of. SWIZ X 1 T means: take the rightmost digit from X and store that to T. Replace the 1 with a 2 and it takes the second digit from the right. That almost works, but not quite, because a row has only 9 columns, so Talisriel had to add one more to X at the end of the row to bump it to 10, and so the second digit becomes the row count.

As you said, that'll cost a bit of time, but I can point out a couple other optimizations to your code:
code:
GRAB 300
LINK 800
MARK LOOP
SWIZ X 2 #DATA
SWIZ X 1 #DATA
COPY F #DATA
ADDI 1 X X
SWIZ X 1 T
TEST T = 9
FJMP NEOL
ADDI 1 X X
MARK NEOL
TEST EOF
TJMP CLEAR
JUMP LOOP
MARK CLEAR
WIPE
Since you need the result of the SWIZ operations only once, you can send it directly to #DATA instead of using T as an intermediate. I also removed the COPY 0 T since that value would be overwritten a couple lines later. 276/17/1

I think fiddling with the order of the tests and jumps could reduce the cycles further, but instead of trying to do that, let's look at what others came up with.

GuavaMoment posted:

You can have one exa feeding in the row data:
code:
LINK 800
MARK LOOP
DIVI X 9 #DATA
ADDI 1 X X
JUMP LOOP
One feeding in the column data:
code:
NOOP
LINK 800
MARK LOOP
MODI X 9 #DATA
ADDI 1 X X
JUMP LOOP
One feeding in data from the file
code:
GRAB 300
NOOP
LINK 800
MARK LOOP
COPY F #DATA
TEST EOF
FJMP LOOP
WIPE
and one to kill everything at the end
code:
NOOP
NOOP
NOOP
LINK 800
COPY 25 X
MARK LOOP
TEST X = 0
SUBI X 1 X
FJMP LOOP
KILL
KILL
86/30/6, still one cycle off top percentage though...
A very clean solution. Each EXA just has a simple loop, taking no more time than it has to, and very readable. I like it. The only quirk it uses is that the first KILL command happens just before the third EXA WIPEs the file. It just happens to kill another EXA first. I have no idea how that's decided by the game but if it works, it works.

Also, what do you mean, top percentage? Wait...





... gods do I feel silly now.
Somehow I managed to always glance over those particular options and I thought you couldn't see this except by guessing it from the histograms. :negative: .

Let's just pretend that never happened.

silentsnack posted:

If you're aiming for the theoretical minimum cycle count, you need your first #DATA input to be on cycle 2 (and then keep writing once every cycle. But as I later noticed we both ran into similar problems with getting the exit/cleanup down to 0 cycles)
code:
;XA
COPY 1 X
LINK 800
NOOP
MARK LOOP
REPL DO_THE_THING
ADDI X 1 X
JUMP LOOP

MARK DO_THE_THING
DIVI X 9 #DATA
MODI X 9 #DATA
COPY M #DATA

;XB
LINK 800
COPY 0 #DATA
COPY 0 #DATA
COPY M #DATA
COPY 38 T
MARK WAIT
SUBI T 1 T
TJMP WAIT
KILL
KILL

;XC
GRAB 300
MARK NOT_3
@REP 2
COPY F M
@END
JUMP NOT_3
84/26/4

This is about where the game starts throwing puzzles at you with enough complexity where it becomes more relevant that when an EXA tries to write to the M register, even if one is already waiting to receive, the sender still has to waste a cycle in the "I'm waiting to send!" state.

Also the @REP in XC needs to be any number that isn't 3 or 9 because if the loop trying to JUMP then XC doesn't crash until another cycle later when trying to arithmetic a nil due to EOF.
Nice. This one has faster cleanup at the end because you never move the file out of your host. XC will stop when it tries to read past the end of file. XB can start sending to #DATA as soon as possible because the first values are always zero anyway, giving XA plenty of time to set up its loop. It uses the parallelism trick of REPL-ing a new EXA while the previous #DATA cycle is still running.

silentsnack posted:

...also it occurs to me that it might be possible to make it even faster. Just gotta crash all EXAs on the same cycle #DATA is finished. The issue with the previous arrangement was being unable to kill XA before XA:26 wrote the last character, but that delay also required killing XA:27 which wasted a cycle.

code:
;XA
MARK LOOP
ADDI X 1 X
NOOP
REPL LOOP

LINK 800
DIVI X 9 #DATA
MODI X 9 #DATA
COPY M #DATA

;XB
LINK 800
COPY 0 #DATA
COPY 0 #DATA
COPY M #DATA

;XC
GRAB 300
@REP 26
COPY F M
@END
KILL
COPY F M
83/41/29

...which turns out to be an even cruder approach, forgoing loops in favor of recursion and bruteforce @REP spam
Ah, again XB handles the first cycle while XA sets itself up. XA lives in the home node where it clones itself constantly and goes into the network to copy to #DATA. That means no other travel is needed and XC, which needs to wait for each XA clone to pick up the M signal anyway, can use a well-timed KILL of XA in the home node, and that's all the clean-up necessary. XC'll just stop and it's not necessary to clean up anything in the home node.

Also, the gif for this one looks quite interesting.



I wish I could cover every small improvement y'all come up with but I feel my updates are getting long enough as they are and it's taking me a lot of time to make sense of each post, so I'm afraid I need to limit myself to those that actually improve the score or are especially interesting or novel. I appreciate every single of your suggestions though so please keep sending them in. If you're reading this from the LP Archive later and you want to know what you missed, go check the discussion in the LP Beach and SA LP threads.


=== Unknown Network 1 ===



I kinda like dead trees too. There's just something to having a real physical copy of some publication in your hands, you know.



Again, I have a choice of two assignments. I'll just do the top one today.

Can friendship exist without self-interest?



Another unanimous vote.

Why couldn't it?

There'd be no point if there weren't benefits to the parties involved?
But maybe it will make sense if I see this in the wild.
Anyway, there is a particular file I need you to locate here.
Don't concern yourself with whatever else you happen to see.
It's all obsolete.


You know, I feel you could go deep into philosophy with this train of thought. If you're friends with someone because spending time with them just makes you happy, does that count as "self-interest" of some sort?

Anyway, let's see what Ember wants from us in this unknown network.


New :siren: OST: Leave No Trace

What the hell is this network? My translator program says that text in the top says NSTU Department of Applied Semiotics, semiotics being the study of signs and symbols.

My assignment is:
- Find file 276 in the network and bring it back to your host.
- Note than an EXA cannot grab a file that is being held by another EXA.


That EXA in the far corner that's not controlled by us is holding a file. That's gotta be the file they're talking about. I guess, go over there, kill that EXA, and take the file home?



What does this mean and what do you want this for, Ember?

code:
LINK 800
LINK 801
LINK 801
LINK 801
KILL
GRAB 276
LINK -1
LINK -1
LINK -1
LINK -1
This is too simple, of course. It works for the initial test run, but the 'enemy EXA' is going to be in a different one of those 8 top-right hosts every test run.
At least bringing back the file is going to be the same every time, since all reverse LINK ids are -1.



This works better. At every step on the way the EXA has to choose which direction to go in. To make it go fast, I just REPL the EXA and have one go left and the other right. I reuse the initial LINK 800 in my little loop since I had it around anyway, and I keep a counter and TEST for it to see if I reached the final hosts and should start grabbing the file. The KILL command does nothing if there's no other EXA there, but GRABbing a non-existing file will cause the EXA to self-destruct. Only the EXA that finds the actual file will survive and will bring it home.





The top percentiles for this one are 15 / 15 / 27. So apparently we did the best we can activity-wise. How about the others?

The size is 16, so we just need to save a single line in this solution to be in the best percentile. What I can do is replace the four LINK -1 lines with this:
code:
MARK RETURN
LINK -1
JUMP RETURN
34/15/27.
That return loop never ends but that doesn't matter - the EXA will blow itself up in the home host once it tries to LINK to a non-existing -1.

For the cycle count, as always it's worth to look into unrolling the loops.

But that's easier said than done since the REPL itself introduces a kind of jump. I tried it anyway.

code:
LINK 800

REPL A
LINK 800
JUMP NEXTB

MARK A
LINK 801

MARK NEXTB

REPL B
LINK 800
JUMP NEXTC

MARK B
LINK 801

MARK NEXTC

REPL C
LINK 800
JUMP NEXTD

MARK C
LINK 801

MARK NEXTD

KILL
GRAB 276
LINK -1
LINK -1
LINK -1
LINK -1
This simply repeats the 800/801 choice three times. Each EXA that doesn't "choose" the REPL then has to jump to the next choice, ignoring the REPL's LINK instruction. It's quite ugly and it feels like we should be able to do (much) better, yet the new score is 18/25/27, which corresponds to that big peak to the left of the cycle histogram.

Shaving off those last three cycles is going to be tricky. Perhaps we can get rid of those unconditional jumps, but most of my ideas would require making more EXAs earlier and that wouldn't save any cycles because only one EXA can traverse any network link at a time.

I also attemped doing something where it tries to find the file after each step. But a GRAB on a non-existing file destroys the EXA, so you'd have to do a REPL first. A REPL blocks the EXA forever if there's no place for the clone (when there's an enemy EXA or even just a file sitting in the other square of the host). So that's not going to work. I'll leave this one to the thread.


Would you say you had friends?



And for the next assignment:

There's another file I want to grab.
They tried to wipe everything clean, but luckily, there's a set of backups.
Always keep a backup, right?




Two votes this time.